GtkCssProvider: Add support for child/descendant combinators.
authorCarlos Garnacho <carlosg@gnome.org>
Fri, 16 Apr 2010 01:02:42 +0000 (03:02 +0200)
committerCarlos Garnacho <carlosg@gnome.org>
Sat, 4 Dec 2010 14:37:06 +0000 (15:37 +0100)
Now, selectors like:

  GtkWindow > GtkButton {}
  GtkNotebook > GtkLabel {}

will represent a direct parent/child relation between both elements, while

  GtkWindow GtkButton {}
  GtkNotebook GtkLabel {}

will allow intermediate children between these.

gtk/gtkcssprovider.c

index 5fdc8828953ece9edd89bb3c15c054b6757804a3..8fbddc2431cd7fcee7fd4723f6010a24cdf6c766 100644 (file)
@@ -33,6 +33,7 @@ typedef struct SelectorElement SelectorElement;
 typedef struct SelectorPath SelectorPath;
 typedef struct SelectorStyleInfo SelectorStyleInfo;
 typedef enum SelectorElementType SelectorElementType;
+typedef enum CombinatorType CombinatorType;
 typedef enum ParserScope ParserScope;
 
 enum SelectorElementType {
@@ -42,9 +43,15 @@ enum SelectorElementType {
   SELECTOR_GLOB
 };
 
+enum CombinatorType {
+  COMBINATOR_DESCENDANT, /* No direct relation needed */
+  COMBINATOR_CHILD       /* Direct child */
+};
+
 struct SelectorElement
 {
   SelectorElementType elem_type;
+  CombinatorType combinator;
 
   union
   {
@@ -150,6 +157,7 @@ selector_path_prepend_type (SelectorPath *path,
   GType type;
 
   elem = g_slice_new (SelectorElement);
+  elem->combinator = COMBINATOR_DESCENDANT;
   type = g_type_from_name (type_name);
 
   if (type == G_TYPE_INVALID)
@@ -173,10 +181,24 @@ selector_path_prepend_glob (SelectorPath *path)
 
   elem = g_slice_new (SelectorElement);
   elem->elem_type = SELECTOR_GLOB;
+  elem->combinator = COMBINATOR_DESCENDANT;
 
   path->elements = g_slist_prepend (path->elements, elem);
 }
 
+static void
+selector_path_prepend_combinator (SelectorPath   *path,
+                                  CombinatorType  combinator)
+{
+  SelectorElement *elem;
+
+  g_assert (path->elements != NULL);
+
+  /* It is actually stored in the last element */
+  elem = path->elements->data;
+  elem->combinator = combinator;
+}
+
 static gint
 selector_path_depth (SelectorPath *path)
 {
@@ -286,8 +308,16 @@ compare_path_foreach (GType        type,
       if (!g_type_is_a (type, elem->type))
         {
           /* Selector definitely doesn't match */
-          data->score = 0;
-          return TRUE;
+          if (elem->combinator == COMBINATOR_CHILD)
+            {
+              data->score = 0;
+              return TRUE;
+            }
+          else
+            {
+              /* Keep checking descendants for a match */
+              return FALSE;
+            }
         }
       else if (type == elem->type)
         data->score |= 0xF;
@@ -614,6 +644,12 @@ parse_selector (GtkCssProvider  *css_provider,
         }
 
       g_scanner_get_next_token (scanner);
+
+      if (scanner->token == '>')
+        {
+          selector_path_prepend_combinator (path, COMBINATOR_CHILD);
+          g_scanner_get_next_token (scanner);
+        }
     }
 
   if (scanner->token == ':')